import abc
from chips.jsonlib.types import *
from chips.jsonlib import schemas

#===============================================================================
# JSONExt base types
#===============================================================================
class ValueExt(object):
    __metaclass__ = abc.ABCMeta
ValueExt.register(Value)

class ContainerExt(object):
    __metaclass__ = abc.ABCMeta
ContainerExt.register(Container)

class JSONExt(object):
    __metaclass__ = abc.ABCMeta
    JSONEXT_TYPES = {}
    JSONEXT_TYPE_NAMES = {}
JSONExt.register(JSON)
JSONExt.register(ValueExt)
JSONExt.register(ContainerExt)

#===============================================================================
# JSONExt interface
#===============================================================================
class IsValueExtMeta(abc.ABCMeta):
    def __new__(cls, name, bases, dict):
        if name == 'IsValueExt':
            return abc.ABCMeta.__new__(cls, name, bases, dict)

        # Create new class and save it
        tt = dict['type']
        dict['schema'] = _schemas.Schema.as_schema(dict['schema'])
        new_type = abc.ABCMeta.__new__(cls, name, bases, dict)
        new_type.register(tt)
        ValueExt.register(tt)

        # Associate original type with this new type and return
        if tt not in JSONExt.JSONEXT_TYPES:
            JSONExt.JSONEXT_TYPES[tt] = new_type
            JSONExt.JSONEXT_TYPE_NAMES[str(tt)[7:-2]] = new_type
            return new_type
        else:
            raise ValueError('type %s is already registered as %s' % (tt, JSONExt.JSONEXT_TYPES[tt]))

class IsValueExt(object):
    __metaclass__ = IsValueExtMeta
    schema = None
    type = None

    @classmethod
    def to_json(cls, obj):
        json_obj = {}
        for k in cls.schema:
            json_obj[k] = getattr(obj, k)
        return cls.schema.compress(json_obj)

    @classmethod
    def from_json(cls, obj):
        return cls.type(**obj)

__all__ = [ 'ValueExt', 'ContainerExt', 'JSONExt', 'JSON', 'IsValueExt', '_schemas']
for k, v in globals().items():
    if isinstance(v, type) and issubclass(v, IsValueExt):
        __all__.append(k)

if __name__ == '__main__':
    import doctest
    doctest.testmod(optionflags=doctest.REPORT_ONLY_FIRST_FAILURE, verbose=0)
